package com.example.jobs.config;

import cn.hutool.extra.spring.SpringUtil;
import com.example.jobs.dao.TaskCronMapper;
import com.example.jobs.task.Task;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronExpression;
import org.springframework.scheduling.support.CronTrigger;

import java.util.Map;

@Slf4j
@Configuration
public class ScheduleTaskConfiguration implements SchedulingConfigurer {

    @Resource
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;

    @Resource
    private TaskCronMapper taskCronMapper;

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        // 设置线程池
        taskRegistrar.setTaskScheduler(threadPoolTaskScheduler);

        Map<String, Task> beansOfType = SpringUtil.getBeansOfType(Task.class);
        log.info("开始注册任务，map: {}", beansOfType);
        for (Task task : beansOfType.values()) {
            taskRegistrar.addTriggerTask(
                    task,
                    // 执行完一次任务后会重新获取下一次运行时间（改完后还会执行一次旧任务，因为上一次执行完后已经获取了下一次的执行时间）
                    triggerContext -> {
                        // 此处查db不会产生日志
                        // 且如果打断点执行时间超过cron的间隔时，不会保证每次任务都执行（Thread starvation）
                        String taskName = task.getTaskName();
                        String cron = taskCronMapper.getCronByTaskName(taskName);
                        log.info("quartz 【{}】最新的cron = {}", taskName, cron);
                        if (checkValid(cron)) {
                            return new CronTrigger(cron).nextExecution(triggerContext);
                        } else {
                            return null;
                        }
                    });
        }
    }

    private static boolean checkValid(String cronExpression) {
        return CronExpression.isValidExpression(cronExpression);
    }

}
